var kBoardWidth = 9;
var kBoardHeight = 9;
var kPieceWidth = 50;
var kPieceHeight = 50;
var kPixelWidth = 1 + (kBoardWidth * kPieceWidth);
var kPixelHeight = 1 + (kBoardHeight * kPieceHeight);

var gCanvasElement;
var gDrawingContext;
var gPattern;

var gPieces;
var gNumPieces;
var gSelectedPieceIndex;
var gSelectedPieceHasMoved;
var gMoveCount;
var gMoveCountElem;
var gGameInProgress;

function Cell(row, column) {
	this.row = row;
	this.column = column;
}

function getCursorPosition(e) {
	/* returns Cell with .row and .column properties */
	var x;
	var y;
	if (e.pageX != undefined && e.pageY != undefined) {
		x = e.pageX;
		y = e.pageY;
	} else {
		x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
		y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
	}
	x -= gCanvasElement.offsetLeft;
	y -= gCanvasElement.offsetTop;
	x = Math.min(x, kBoardWidth * kPieceWidth);
	y = Math.min(y, kBoardHeight * kPieceHeight);
	var cell = new Cell(Math.floor(y / kPieceHeight), Math.floor(x / kPieceWidth));
	return cell;
}

function halmaOnClick(e) {
	var cell = getCursorPosition(e);
	for (var i = 0; i < gNumPieces; i++) {
		if ((gPieces[i].row == cell.row) && (gPieces[i].column == cell.column)) {
			clickOnPiece(i);
			return;
		}
	}
	clickOnEmptyCell(cell);
}

function clickOnEmptyCell(cell) {
	if (gSelectedPieceIndex == -1) {
		return;
	}

	var rowDiff = Math.abs(cell.row - gPieces[gSelectedPieceIndex].column);
	if ((rowDiff <= 1) && (columnDiff <= 1)) {
		/* we already know that this click was on an empty square,
		   so that must mean this was a valid single-square move */
		gPieces[gSelectedPieceIndex].row = cell.row;
		gPieces[gSelectedPieceIndex].column = cell.column;
		gMoveCount += 1;
		gSelectedPieceIndex = -1;
		gSelectedPieceHasMoved = false;
		drawBoard();
		return;
	}
	if (((rowDiff == 2) && (columnDiff == 0)) || ((rowDiff == 0) && (columnDiff == 2)) || ((rowDiff == 2) && (columnDiff == 2)) && isThereAPicecBetween(gPieces[gSelectedPieceIndex], cell)) {
		/* this was a valid jump */
		if (!gSelectedPieceHasMoved) {
			gMoveCount += 1;
		}
		gSelectedPieceIndex = -1;
		gSelectedPieceHasMoved = false;
		drawBoard();
	}
}

function clickOnPiece(pieceIndex) {
	if (gSelectedPieceIndex == pieceIndex) {
		return;
	}
	gSelectedPieceIndex = pieceIndex;
	gSelectedPieceHasMoved = false;
	drawBoard();
}

function isThereAPieceBetween(cell1, cell2) {
	/* note: assumes cell1 and cell2 are 2 squares away
       either vertically, horizontally, or diagonally */
	var rowBetween = (cell1.row + cell2.row) / 2;
	var columnBetween = (cell1.column + cell2.column) / 2;
	for (var i = 0; i < gNumPieces; i++) {
		if ((gPieces[i].row == rowBetween) &&
			(gPieces[i].column == columnBetween)) {
			return true;
		}
	}
	return false;
}

function isTheGameOver() {
	for (var i = 0; i < gNumPieces; i++) {
		if (gPieces[i].row > 2) {
			return false;
		}
		if (gPieces[i].column < (kBoardWidth - 3)) {
			return false;
		}
	}
	return true;
}

function drawBoard() {
	if (gGameInProgress && isTheGameOver()) {
		endGame();
	}

	gDrawingContext.clearRect(0, 0, kPixelWidth, kPixelHeight);

	gDrawingContext.beginPath();

	/* vertical lines */
	for (var x = 0; x <= kPixelWidth; x += kPieceWidth) {
		gDrawingContext.moveTo(0.5 + x, 0);
		gDrawingContext.lineTo(0.5 + x, kPixelHeight);
	}

	/* horizontal lines */
	for (var y = 0; y <= kPixelHeight; y += kPieceHeight) {
		gDrawingContext.moveTo(0, 0.5 + y);
		gDrawingContext.lineTo(kPixelWidth, 0.5 + y);
	}

	/* draw it! */
	gDrawingContext.strokeStyle = "#ccc";
	gDrawingContext.stroke();

	for (var i = 0; i < 9; i++) {
		drawPiece(gPieces[i], i == gSelectedPieceIndex);
	}

	gMoveCountElem.innerHTML = gMoveCount;

	saveGameState();
}

function drawPiece(p, selected) {
	var column = p.column;
	var row = p.row;
	var x = (column * kPieceWidth) + (kPieceWidth / 2);
	var y = (row * kPieceHeight) + (kPieceHeight / 2);
	var radius = (kPieceWidth / 2) - (kPieceWidth / 10);
	gDrawingContext.beginPath();
	gDrawingContext.arc(x, y, radius, 0, Math.PI * 2, false);
	gDrawingContext.closePath();
	gDrawingContext.strokeStyle = "#000";
	gDrawingContext.stroke();
	if (selected) {
		gDrawingContext.fillStyle = "#000";
		gDrawingContext.fill();
	}
}

if (typeof resumeGame != "function") {
	saveGameState = function () {
		return false;
	}
	resumeGame = function () {
		return false;
	}
}

function newGame() {
	gPieces = [new Cell(kBoardHeight - 3, 0),
			   new Cell(kBoardHeight - 2, 0),
			   new Cell(kBoardHeight - 1, 0),
			   new Cell(kBoardHeight - 3, 1),
			   new Cell(kBoardHeight - 2, 1),
			   new Cell(kBoardHeight - 1, 1),
			   new Cell(kBoardHeight - 3, 2),
			   new Cell(kBoardHeight - 2, 2),
			   new Cell(kBoardHeight - 1, 2),
			  ];
	gNumPieces = gPieces.length;
	gSelectedPieceIndex = -1;
	gSelectedPieceHasMoved = false;
	gMoveCount = 0;
	gGameInProgress = true;
	drawBoard();
}

function endGame() {
	gSelectedPieceIndex = -1;
	gGameInProgress = false;
}

function initGame(canvasElement, moveCountElemnt) {
	if (!canvasElement) {
		canvasElement = document.createElement("canvas");
		canvasElement.id = "halma_canvas";
		document.body.appendChild(canvasElement);
	}
	if (!moveCountElemnt) {
		moveCountElemnt = document.createElement("p");
		document.body.appendChild(moveCountElemnt);
	}
	gCanvasElement = canvasElement;
	gCanvasElement.width = kPixelWidth;
	gCanvasElement.height = kPixelHeight;
	gCanvasElement.addEventListener("click", halmaOnClick, false);
	gMoveCountElem = moveCountElemnt;
	gDrawingContext = gCanvasElement.getContext("2d");
	if (!resumeGame()) {
		newGame();
	}
}